----------------------------------------------------------------------
----------------------------------------------------------------------
DOCUMENT:
PROGRAMMING DMA I/O WITH VMDMA
Version 1.0
March 8, 1991
Programming and Documentation by Ryan Hanlon
Copyright (c) 1991, Covox, Inc. All Rights Reserved
----------------------------------------------------------------------
GENERAL DESCRIPTION
The recording and playback of non-compressed 8 bit PCM sound
data via DMA (memory to port, port to memory), can be achieved
by setting the Voice Master card and mother board DMA controller
properly. This document will supply all of the raw information
you will need to write recording and playback software for the
Voice Master and the Sound Master II boards.
The Voice Master is only capable of being set to use IRQ 3 or IRQ 7
while the Sound Master II board can use any one of IRQ's 3 through 7.
Both the Voice Master and the Sound Master II were designed to use
DMA channel 1 or channel 3 and one of the port ranges starting at
0x0220, 0x0240, 0x0280, or 0x02C0.
NOTE : Except for the IRQ changes on the Sound Master II the
functionality of the Voice Master is replicated on the Sound
Master II board. For the duration of this document all references
to the Voice Master (VMDMA), apply equally to the Sound Master II
board.
This document should be used in conjunction with the document and
source code supplied with the program sm2detec.exe.
----------------------------------------------------------------------
VOICE MASTER PORTS
BASE PORTS
Jumper setting positions 1 through 4 determine the BASE PORT of
the Voice Master.
0x0220 to 0x022F,
0x0240 to 0x024F,
0x0280 to 0x028F,
0x02C0 to 0x02CF
BASE PORT OFFSETS
The BASE PORT plus (+) the BASE PORT OFFSET can be used to access the
ports on the Voice Master. As can be seen below only port offsets
from 0x08 and 0x0F are used on the Voice Master.
8254 TIMER 0 OFFSET = 0x08 Timer/Clock
8254 TIMER 1 OFFSET = 0x09 Timer/Clock
8254 TIMER 2 OFFSET = 0x0A Timer/Clock
8254 CONTROL OFFSET = 0x0B Timer/Clock control register
CLEAR IRQ OFFSET = 0x0C \
DISABLE VMDMA OFFSET = 0x0D > VMDMA Control ports
ENABLE VMDMA OFFSET = 0x0E /
DAC OFFSET = 0x0F The DAC OFFSET port should
not be written to during DMA
i/o.
----------------------------------------------------------------------
VMDMA CONTROL PORT OFFSETS
DISABLE DMA OFFSET = 0x0D
Writing to this port will disable DREQ (DMA Request), channel 1
or DREQ channel 3 thus preventing all VMDMA i/o.
ENABLE DMA OFFSET = 0x0E
Writing to this port should be done last and only after all clock and
DMA setup has been completed. A write to this port will fire off
a DREQ (cause the DREQ line to go low), thus allowing the VMDMA i/o
to begin.
CLEAR IRQ OFFSET = 0x0C
This BASE PORT offset is to be utilized after every DMA
terminal count is reached. It is common to find this port
being written to inside an interrupt handler. Any value
may be output to the port.
----------------------------------------------------------------------
INTEL 8254 COUNTER/TIMER ONBOARD THE VOICE MASTER
The Voice Master is equipped with the Intel 8254 programmable interval
counter/timer. COUNTER 2 is used for DMA i/o control. COUNTER 1 and 3
are not used by the Voice Master and are available for general purpose
use within software.
TIMER 0 OFFSET = 0x08 TIMER 1 OFFSET = 0x09 TIMER 2 OFFSET = 0x0A
8254 CONTROL OFFSET = 0x0B
COUNTER 2 is setup to fire off DREQ's at given intervals by
latching to the 8254 CONTROL OFFSET port in LSB/MSB order.
The formula you will need to properly program this DREQ
frequency is shown below.
7.1MHz
i/o rate = ------------ where N is a 16 bit divisor that
N is written, 8 bits at a time,
to one of the TIMER OFFSETs.
Each DREQ sent by the Voice Master is received by the 8237 DMA
controller on the mother board. After one 8 bit DMA read or write is
performed the 8237 sends a DACK (DMA Acknowledged), signal to the Voice
Master board. This DACK signal effectively disables the Voice Master
from sending another DREQ to the 8237 until CLOCK 2 reaches zero again.
Bit settings for the CONTROL port of the 8254.
bits 7,6 = 00 timer 0 bits 5,4 = 00 latch preset
01 timer 1 01 read/write only MSB
10 timer 2 10 read/write only LSB
01 read/write LSB, then MSB
bits 3,1 = 000 mode 0 bit 0 = 0 binary
001 mode 1 1 BCD decrementing
010 mode 2
011 mode 3
100 mode 4
101 mode 5
----------------------------------------------------------------------
8237 DMA CONTROLLER ON THE MOTHERBOARD
The DMA on the mother board should be completely setup for i/o
only after the Voice Master board has had the DREQ lines
disabled. (See DISABLE VMDMA OFFSET for more information).
The recommended settings for performing recording or playback
are as follows :
1. single mode
2. address increment
3. no automatic reinitialize
4. read or write (depending on desired results)
5. channel 1 or 3 (depending on jumper setting on Voice Master)
Bit settings for the control byte of the 8237.
bits 7,6 = 00 demand mode
01 single mode
10 block mode
11 cascade mode
bit 5 = 0 address increment
1 address decrement
bit 4 = 0 no automatic reinitialize
1 automatic reinitialize
bits 3,2 = 00 verify
01 write
10 read
bits 1,0 = 00 channel 0
01 channel 1
10 channel 2
11 channel 3
----------------------------------------------------------------------
DMA BUFFER - 20-BIT SEGMENT ADDRESS
Bits 2 and 3 of the byte written to the 8237 DMA CONTROLLER determine
whether DMA recording or playback will be performed. Both DMA i/o
directions require that the start address of a data buffer be output
to the DMA ADDRESS REGISTER and the physical page be outp to the
DMA PAGE REGISTER.
EXAMPLE :
This example uses a long named temp_address to store the 20 bit
address of a Test_Buffer of char. First the page address of Test_Buffer
is outp to the DMA PAGE REGISTER. The remaining 16 bit address
is outp to the DMA ADDR REGISTER. Channel 1 is the active settings
of the Voice Master for this example.
/* Get 20 bit address of test buffer
*/
temp_address = ((long)FP_SEG(Test_Buffer))<<4) + (long)FP_OFF(Test_Buffer);
/* Output segment page address of test buffer to the DMA PAGE REGISTER
// for channel 1.
*/
outp( DMA_CH1_PAGE_REGISTER, (unsigned char)(temp_address >> 16) );
/* Set the address of the test buffer. outp LSB then MSB.
*/
outp( DMA_CLEAR_LSB_MSB, 0x00 );
outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address) );
outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address >> 8) );
----------------------------------------------------------------------
DMA BUFFER - CURRENT BUFFER SIZE
The size of the current buffer being used with DMA i/o should be
output to the DMA COUNT REGISTER. Special considerations need to be
made for buffers that cross page boundaries.
EXAMPLE :
This example assumes that the length of Test_Buffer is stored in a
variable named Test_Buffer_Count. Since the DMA predecrements this
count before a byte is processed we add 1 to the count before it
is outp to the DMA COUNT REGISTER. Channel 1 is the active settings
of the Voice Master for this example.
This example does not check to see if the length of the buffer exceeds
the available length left before the page boundary.
/* Set word count on DMA channel 1.
*/
outp( DMA_CLEAR_LSB_MSB, 0x00 );
outp( DMA_CH1_COUNT_REGISTER, Test_Buffer_Count + 1 );
outp( DMA_CH1_COUNT_REGISTER, 0x00 );
/* Enable 8237 DMA on the mother board
*/
outp( DMA_MASK_REGISTER , DMA_CH1);
----------------------------------------------------------------------
IMPORTANT PROGRAMMING CONSIDERATIONS
1. Disabling and enabling of the DMA subsystem can cause an IRQ to fire
off.
2. When the terminal count is reached on the 8237 DMA controller the
DACK line on the Voice Master goes high. To set this line to
low and thus allow the next interrupt to occur you must
outp( (vmdma_base_port + VMDMA_CLEAR_IRQ_OFFSET), 0) directly before
issuing an outp(0x20,0x20) in your interrupt handler.